home *** CD-ROM | disk | FTP | other *** search
/ SPACE 2 / SPACE - Library 2 - Volume 1.iso / utility / 541 / midi / midipl04 / mp_intp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-07-21  |  13.1 KB  |  560 lines

  1. /*
  2.  * File: mp_intp.c
  3.  * SGoldthorpe    20-Jul-91
  4.  */
  5.  
  6. /*
  7.  * mp_intp - the midi file interpreter for midiplay
  8.  * This software is (C) 1991 Stephen Goldthorpe but it's FREE!  Usual
  9.  * disclaimers and notices about this software not being sold for profit.
  10.  * But you may take all you want from the code though!  If you have any
  11.  * suggestions/bug fixes please get in contact with me.  I don't want to
  12.  * maintain code i've never even seen before (life's hard enough without all
  13.  * of that)!
  14.  *                        -Steve Goldthorpe
  15.  * Phone (DAYTIME UK):    +44 707 382350
  16.  * Internet E-Mail:    SGoldthorpe.wgc-e@rx.xerox.com
  17.  *            goldthor@arisia.xerox.com
  18.  */
  19.  
  20. #include    <stdio.h>
  21. #include    <types.h>
  22. #include    <time.h>
  23. #include    <string.h>
  24.  
  25. /* and for the atari OS stuff */
  26. #include    <osbind.h>
  27.  
  28. /* #include    "midiplay.h" included by mp_gbls.h */
  29. #include    "mp_gbls.h"
  30.  
  31. /* GLOBAL VARIABLES */
  32. static double    track_delta[MAX_TRACKS], division, time_per_beat;
  33. static BYTE    *track_pos[MAX_TRACKS];
  34. static int    track_left[MAX_TRACKS];
  35. static int    track_finished[MAX_TRACKS];
  36. static clock_t    clock_orig;
  37. static char    *gFile;
  38. static WORD    format, tracks;
  39. static int    finished_tracks;
  40. static int    i;
  41.  
  42. /* FUNCTION DECLS */
  43. BOOL        interp();
  44. static void    truncated(), all_notes_off(), parse_error();
  45.  
  46. /* MACRO FUNCTIONS */
  47. /* the error checking may be a bit OTT but I'm gonna do it anyway  (helps
  48.    catch those naughty bugs - and bad files) */
  49. #define GET32BITS(dw,p,l)    dw=(((LONG)(*p)<<24)+            \
  50.                     ((LONG)(*(p+1))<<16)+        \
  51.                     (((LONG)*(p+2))<<8)+        \
  52.                     (LONG)(*(p+3)));        \
  53.                 if(l<4)                    \
  54.                 {    truncated();            \
  55.                     return(FALSE);            \
  56.                 };                    \
  57.                 p += 4; l -= 4
  58.  
  59. #define    GET16BITS(w,p,l)    w=(((WORD)(*p)<<8)+(WORD)*(p+1));    \
  60.                 if(l<2)                    \
  61.                 {    truncated();            \
  62.                     return(FALSE);            \
  63.                 }                    \
  64.                 p += 2; l -= 2
  65.  
  66. #define    GET8BITS(b,p,l)        b = *(p)++;                \
  67.                 if(--l<0)                \
  68.                 {    truncated();            \
  69.                     return(FALSE);            \
  70.                 }
  71.  
  72. #define    GETVARLEN(dw,p,l)    for(dw=(LONG)(*p)&0x7f;(*(p)++)&0x80;)    \
  73.                 {    if(--l<0)            \
  74.                     {    truncated();        \
  75.                         return(FALSE);        \
  76.                     };                \
  77.                     dw <<=7;            \
  78.                     dw |= (LONG)(*p)&0x7f;        \
  79.                 };                    \
  80.                 if(--l<0)                \
  81.                 {    truncated();            \
  82.                     return(FALSE);            \
  83.                 }
  84.  
  85. #define    CHECKLEFT(l,v)        if(l<v)                    \
  86.                 {    truncated();            \
  87.                     return(FALSE);            \
  88.                 }
  89.  
  90. #define    SEND(b)            Bconout(3,b)
  91.  
  92. /* FUNCTION DEFS */
  93. BOOL        interp(buffer, file, len)
  94. char        *file;
  95. BYTE        *buffer;
  96. unsigned int    len;
  97. {   BYTE    *pos=buffer,*next;
  98.     BYTE    running_status[MAX_TRACKS],last_running_status;
  99.     WORD    w;
  100.     LONG    dw,delta;
  101.     double    clock_delta;
  102.     unsigned int left=len;
  103.  
  104.     gFile=file;
  105.  
  106.     /* check header */
  107.     if((left<4)||(strncmp("MThd",(char*)pos,4)!=0))
  108.     {    (void)fprintf(stderr,"%s: %s is not a midi file\n",app_name,file);
  109.     return(FALSE);
  110.     };
  111.     pos += 4; left -= 4;
  112.  
  113.     /* find address of next chunk */
  114.     GET32BITS(dw,pos,left);
  115.     next=pos+dw;
  116. #ifdef DEBUG
  117.     (void)printf("pos is %lx len is %ld next would be %lx\n",pos-buffer,dw,
  118.     next-buffer);
  119. #endif
  120.  
  121.     /* get file format */
  122.     GET16BITS(format,pos,left);
  123.     switch (format)
  124.     {    /* OK we accept formats 0 and 1 */
  125.     case 0:
  126.     case 1:
  127.              break;
  128.     /* but we don't do any others */
  129.     default:
  130.     (void)fprintf(stderr,"%s: can't play %s, midi file type %d\n",app_name,
  131.         file,format);
  132.     return(FALSE);
  133.     };
  134.  
  135.     /* get number of tracks */
  136.     GET16BITS(tracks,pos,left);
  137.  
  138.     /* check tracks in range */
  139.     if(tracks > MAX_TRACKS)
  140.     {    (void)fprintf(stderr,"%s: %s has too many tracks (%d allowed).\n",
  141.         app_name,file,tracks,MAX_TRACKS);
  142.     return(FALSE);
  143.     };
  144.  
  145.     /* get division - this is the division of a quarter note or if negative is
  146.        frame based. */
  147.     GET16BITS(w,pos,left);
  148.     division=(double)w;
  149.  
  150.     /* I don't suport the frame stuff yet! */
  151.     if(division < 0)
  152.     {    (void)fprintf(stderr,
  153.         "%s: file %s - don't support framed based files yet!", app_name,
  154.         file);
  155.     return(FALSE);
  156.     };
  157. #ifdef DEBUG
  158.     (void)printf("division = %f\n",division);
  159. #endif
  160.  
  161.     time_per_beat = (double)(CLK_TCK * 60.0)/120.0; /* default 120bpm */
  162. #ifdef DEBUG
  163.     (void)printf("time per beat (1/200 sec) %f\n",time_per_beat);
  164. #endif
  165.  
  166.     /* do some initialisation, track finding etc */
  167.     finished_tracks = 0;
  168.     for(i=0;i<tracks;i++)
  169.     {    CHECKLEFT(left,(next-pos));
  170.     left -= next-pos; pos = next;
  171.  
  172.     /* track start  */
  173.     if((left<4)||(strncmp("MTrk",(char*)pos,4)!=0))
  174.     {   (void)fprintf(stderr,"%s: %s parse error, track expected\n",
  175.         app_name,file);
  176. #ifdef DEBUG
  177.         (void)printf("posn %lx, bytes around (-3..3) %02x %02x %02x %02x \
  178. %02x %02x %02x\n",pos-buffer,*(pos-3),*(pos-2),*(pos-1),*pos,*(pos+1),*(pos+2),
  179.         *(pos+3));
  180. #endif
  181.         return(FALSE);
  182.     };
  183.     pos += 4; left -= 4;
  184.  
  185.     /* find address of next chunk */
  186.     GET32BITS(dw,pos,left);
  187.     *(track_pos+i) = pos;
  188.     next = pos+dw;
  189.     *(track_left+i) = (int)dw;
  190. #ifdef DEBUG
  191.     (void)printf("pos is %lx len is %ld next would be %lx\n",pos-buffer,dw,
  192.         next-buffer);
  193. #endif
  194.  
  195.     /* get initial delta time */
  196.     GETVARLEN(dw,*(track_pos+i),*(track_left+i));
  197.     *(track_delta+i)=(double)dw;
  198.     *(track_finished+i)=FALSE;
  199.     *(running_status+i) = 0xfe;
  200.     last_running_status = 0xfe;
  201.     };
  202.  
  203.     /* let the user know what's happening */
  204.     (void)printf("playing '%s' with %d tracks\n",file,tracks);
  205.  
  206.     /* get start time */
  207.     clock_orig=clock();
  208.  
  209.     /* dispatcher */
  210.     while (finished_tracks != tracks)
  211.     {    BYTE    event;
  212.     clock_delta = (double)(clock()-clock_orig)*division/time_per_beat;
  213.     for(i=0;i<tracks;i++)
  214.     {   if(!*(track_finished+i) & (clock_delta>*(track_delta+i)))
  215.         {    GET8BITS(event,*(track_pos+i),*(track_left+i));
  216.  
  217.         /* parse event */
  218.         switch (event)
  219.         {   /* meta-events */
  220.             case 0xff:
  221.             {    if(!meta_event())
  222.                 return(FALSE);
  223.             break;
  224.             };
  225.             /* sysex events */
  226.             case 0xf0:
  227.             case 0xf7:
  228.             {    if(!sysex_event(event))
  229.                 return(FALSE);
  230.             break;
  231.             };
  232.             case 0xf1:
  233.             case 0xf2:
  234.             case 0xf3:
  235.             case 0xf4:
  236.             case 0xf5:
  237.             case 0xf6:
  238.             {    if(!system_common(event))
  239.                 return(FALSE);
  240.             break;
  241.             };
  242.             case 0xf8:
  243.             case 0xf9:
  244.             case 0xfa:
  245.             case 0xfb:
  246.             case 0xfc:
  247.             case 0xfd:
  248.             case 0xfe:
  249.             {    if(!system_real_time())
  250.                 return(FALSE);
  251.             break;
  252.             };
  253.             /* midi events */
  254.             default:
  255.             {    switch(event & 0xf0)
  256.             {   /* 3 byte events */
  257.                 case 0x90:
  258.                 case 0x80:
  259.                 case 0xa0:
  260.                 case 0xb0:
  261.                 case 0xe0:
  262.                 {    BYTE    c;
  263.                 SEND(event);
  264.                 GET8BITS(c,*(track_pos+i),*(track_left+i));
  265.                 SEND(c);
  266.                 GET8BITS(c,*(track_pos+i),*(track_left+i));
  267.                 SEND(c);
  268.                 *(running_status+i) = event;
  269.                 last_running_status = event;
  270.                 break;
  271.                 };
  272.                 /* program change */
  273.                 case 0xc0:
  274.                 {    BYTE    c;
  275.                 GET8BITS(c,*(track_pos+i),*(track_left+i));
  276.                 if (f_Program)
  277.                 {   SEND(event);
  278.                     SEND(c);
  279.                     *(running_status+i) = event;
  280.                     last_running_status = event;
  281.                 };
  282.                 break;
  283.                 };
  284.                 /* channel pressure */
  285.                 case 0xd0:
  286.                 {    BYTE    c;
  287.                 GET8BITS(c,*(track_pos+i),*(track_left+i));
  288.                 if (f_Channel_pressure)
  289.                 {   SEND(event);
  290.                     SEND(c);
  291.                     *(running_status+i) = event;
  292.                     last_running_status = event;
  293.                 };
  294.                 break;
  295.                 };
  296.                 default:
  297.                 {    /* running status */
  298.                 if(*(running_status+i)!=last_running_status)
  299.                 {   SEND(*(running_status+i));
  300.                     last_running_status=*(running_status+i);
  301.                 };
  302.                 if((event&0x80)==0)
  303.                 {   SEND(event);
  304. #ifdef DEBUG
  305.                     (void)printf("running stat (%02x)  %02x\n",
  306.                     *(running_status+i),event);
  307. #endif
  308.                     switch(*(running_status+i) & 0xf0)
  309.                     {   /* 3 byte events */
  310.                     case 0x90:
  311.                     case 0x80:
  312.                     case 0xa0:
  313.                     case 0xb0:
  314.                     case 0xe0:
  315.                     {   BYTE c;
  316.                         GET8BITS(c,*(track_pos+i),
  317.                         *(track_left+i));
  318.                         SEND(c);
  319.                         break;
  320.                     };
  321.                     /* ignoring other 0xf? events - naughty
  322.                         aren't I */
  323.                     };
  324.                 };
  325.                 };
  326.             };
  327.             };
  328.         };
  329.  
  330.         /* get delta time  - but only if we're still going on this
  331.            track */
  332.         if(!*(track_finished+i))
  333.         {   GETVARLEN(delta,*(track_pos+i),*(track_left+i));
  334.             *(track_delta+i) += (double)delta;
  335.         };
  336.         };
  337.     };
  338.     /* CHECK TO SEE IF CTRL C/S PRESSED */
  339.     if(Bconstat(2))
  340.     {   BYTE    c;
  341.         c=(Bconin(2)&0xff);
  342.         switch(c)
  343.         {    case 3: /* CTRL C */
  344.         {   printf("\n** Exit by CTRL C **\n");
  345.             all_notes_off();
  346.             return(TRUE);
  347.         };
  348.         case 19: /* CTRL S */
  349.         {   printf("\n** Skip track by CTRL S **\n");
  350.             all_notes_off();
  351.             return(FALSE);
  352.         };
  353.         };
  354.     };
  355.     };
  356.     return(FALSE);
  357. };
  358.  
  359. /* system exclusive events */
  360. int    sysex_event(event)
  361. BYTE    event;
  362. {   LONG    length,l;
  363.     GETVARLEN(length,*(track_pos+i),*(track_left+i));
  364.     if(f_Sysex)
  365.     {   BYTE    c;
  366.     if(event==0xf0)
  367.         SEND(0xf0);
  368.     for(l=0;l<length;l++)
  369.     {  GET8BITS(c,*(track_pos+i),*(track_left+i));
  370.        SEND(c);
  371.     };
  372.     }
  373.     else
  374.     {   CHECKLEFT(*(track_left+i),(int)length);
  375.         *(track_pos+i) += length;
  376.         *(track_left+i) -= length;
  377.     };
  378.     return(TRUE);
  379. };
  380.  
  381. /* meta-events */
  382. int meta_event()
  383. {   BYTE    type;
  384.     LONG    length;
  385.  
  386.     /* get type of meta event */
  387.     GET8BITS(type,*(track_pos+i),*(track_left+i));
  388. #ifdef DEBUG
  389.     (void)printf("meta-event %02x ",type);
  390. #endif
  391.  
  392.     /* get length */
  393.     GETVARLEN(length,*(track_pos+i),*(track_left+i));
  394. #ifdef DEBUG
  395.     (void)printf("length %ld\n",length);
  396. #endif
  397.  
  398.     switch(type)
  399.     {    /* textual meta-events */
  400.     case 0x01:
  401.     case 0x02:
  402.     case 0x03:
  403.     case 0x04:
  404.     case 0x05:
  405.     case 0x06:
  406.     case 0x07:
  407.     {   int        flag;
  408.         char    *msg;
  409.         switch(type)
  410.         {    case 0x01:
  411.             flag=f_text;
  412.             msg="Text: \"";
  413.             break;
  414.          case 0x02:
  415.             flag=f_copyright;
  416.             msg="Copyright: \"";
  417.             break;
  418.         case 0x03:
  419.             flag=f_track_name;
  420.             msg="Track\Sequence: \"";
  421.             break;
  422.         case 0x04:
  423.             flag=f_instrument;
  424.             msg="Instrument: \"";
  425.             break;
  426.         case 0x05:
  427.             flag=f_lyric;
  428.             break;
  429.         case 0x06:
  430.             flag=f_marker;
  431.             msg="Marker: \"";
  432.             break;
  433.         case 0x07:
  434.             flag=f_prompt;
  435.             msg="Prompt: \"";
  436.             break;
  437.         };
  438.         if (flag)
  439.         {    LONG    l;
  440.         BYTE    c;
  441.         /* lyrics should have no header */
  442.             if(type!=0x05)
  443.             printf(msg);
  444.         for(l=0;l<length;l++)
  445.         {   GET8BITS(c,*(track_pos+i),*(track_left+i));
  446.             putchar(c);
  447.         };
  448.         /* lyrics should be on same line */
  449.         if(type!=0x05)
  450.             printf("\"[Tr %d]\n",i);
  451.         }
  452.         else
  453.         {    CHECKLEFT(*(track_left+i),(int)length);
  454.         *(track_pos+i) += length;
  455.         *(track_left+i) -= length;
  456.         };
  457.         break;
  458.     };
  459.     /* u-sec tempo set */
  460.     case 0x51:
  461.     {   LONG    t;
  462.         BYTE    c;
  463.         GET8BITS(c,*(track_pos+i),*(track_left+i));
  464.         t=(LONG)c<<16;
  465.         GET8BITS(c,*(track_pos+i),*(track_left+i));
  466.         t += (LONG)c<<8;
  467.         GET8BITS(c,*(track_pos+i),*(track_left+i));
  468.         t += (LONG)c;
  469. #ifdef DEBUG
  470.         (void)printf("usec %ld ",t);
  471. #endif
  472.         t=(t*(LONG)CLK_TCK)/1000000L;
  473.         time_per_beat = (double)t;
  474. #ifdef DEBUG
  475.         (void)printf("our %f\n",time_per_beat);
  476. #endif
  477.         break;
  478.     };
  479.  
  480.     /* end of track - can't be bothered to check left == 0 too */
  481.     case 0x2f:
  482.         *(track_finished+i)=TRUE;
  483.         finished_tracks++;
  484.         break;
  485.  
  486.         /* ignore rest */
  487.     default:
  488.         CHECKLEFT(*(track_left+i),(int)length);
  489.         *(track_pos+i) += length;
  490.         *(track_left+i) -= length;
  491.         break;
  492.     };
  493.     return(TRUE);
  494. };
  495.  
  496. static int    system_common(event)
  497. BYTE    event;
  498. {   switch(event)
  499.     {    /* 3 byte instructions */
  500.     case 0xf2:
  501.     {   CHECKLEFT(*(track_left+i),2);
  502.         *(track_pos+i) += 2;
  503.         *(track_left+i) -= 2;
  504.         break;
  505.     };
  506.     /* 2 byte instructions */
  507.     case 0xf1:
  508.     case 0xf3:
  509.     {   CHECKLEFT(*(track_left+i),1);
  510.         *(track_pos+i) += 1;
  511.         *(track_left+i) -= 1;
  512.         break;
  513.     };
  514.     /* rest are single byte */
  515.     };
  516.     return(TRUE);
  517. };
  518.  
  519. static int    system_real_time()
  520. {    /* all 1 byte so ignore */
  521.     return(TRUE);
  522. };
  523.  
  524. static void    all_notes_off()
  525. {   /* MANUALLY TURN ALL NOTES OFF */
  526.     /* time= (2+8)x16x(1+128x2)/31250 ~= 1.5 seconds */
  527.     int    i,j;
  528.     for(i=0;i<16;i++)
  529.     {    SEND((BYTE)(0x90+i));
  530.     for(j=0;j<128;j++)
  531.     {   SEND((BYTE)j);
  532.         SEND(0);
  533.     };
  534.     };
  535. };
  536.  
  537. /* general error messages - I got fed up typing these over and over again */
  538. static void    truncated()
  539. {   (void)fprintf(stderr,"%s: %s truncated\n",app_name,gFile);
  540. };
  541.  
  542. /*
  543.  * REVISION LOG
  544.  * ============
  545.  * 0.1    SGoldthorpe    20-Mar-91    Created for Atari ST / Sozobon C.  It's
  546.  *                    a bit atari specific in places but i've
  547.  *                    tried to make it UNIX(tm) looking for
  548.  *                    easier porting (if anyone feels brave
  549.  *                    enough to try.
  550.  * 0.2    SGoldthorpe     7-Apr-91    Messed up the code in mp_intp to
  551.  *                    allow type 1 midi files.  Timing is
  552.  *                    still a bit hairy but it plays 80%
  553.  *                    of the files I have OK.
  554.  * 0.3    SGoldthorpe    27-May-91    Reformatted & tidied up, sorted out
  555.  *                    running status and added flags.
  556.  * 0.4    SGoldthorpe    20-Jul-91    Generally restructed and tidied up and
  557.  *                    added sysex events.
  558.  *
  559.  */
  560.